"""
告警业务逻辑层
处理告警相关的业务逻辑
"""

import os
import threading
from typing import List, Optional
from datetime import datetime
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

from backend.models.alarm import Alarm, AlarmCreate, AlarmQuery, AnalysisResult
from backend.database import (
    init_db,
    insert_alarm,
    get_alarms,
    get_alarm_by_id,
    query_alarms,
    get_alarms_count,
    get_alarm_statistics
)

# 导入原有的邮件发送模块
from backend.api import send_mail
# 导入原有的Excel分析模块
from backend.api import alarm_analyze
# 导入路径工具函数
from backend.utils.path_helper import (
    get_wechat_file_base_path,
    get_analysis_results_path,
    find_latest_alarm_excel
)
# 导入配置读取工具
from backend.utils.config_reader import get_email_config, get_smtp_config


# ==================== Excel文件监听事件处理器 ====================
class ExcelFileHandler(FileSystemEventHandler):
    """
    Excel文件监听事件处理器
    监听指定目录下的Excel文件创建事件
    只处理以"告警导出"开头的.xlsx文件
    """
    def __init__(self, alarm_service):
        self.processed_files = set()
        self.alarm_service = alarm_service
    
    def on_created(self, event):
        """文件创建事件处理"""
        if not event.is_directory:
            file_path = str(event.src_path)
            file_name = os.path.basename(file_path)
            
            # 只处理.xlsx文件
            if file_path.endswith('.xlsx'):
                # 只处理以"告警导出"开头的文件
                if file_name.startswith('告警导出'):
                    if file_path not in self.processed_files:
                        print(f"✅ 发现新的告警导出Excel文件: {file_name}")
                        self.processed_files.add(file_path)
                        # 记录最新发现的文件
                        self.alarm_service.latest_file = {
                            'file_name': file_name,
                            'file_path': file_path,
                            'timestamp': datetime.now().isoformat()
                        }


class AlarmService:
    """告警服务类 - 处理告警相关的业务逻辑"""
    
    def __init__(self):
        # 初始化数据库表
        init_db()
        # 文件监听线程
        self.monitor_thread = None
        self.monitoring = False
        # 最新发现的告警导出文件
        self.latest_file = None
    
    def create_alarm(self, alarm: AlarmCreate) -> bool:
        """创建告警记录"""
        try:
            insert_alarm(alarm)
            return True
        except Exception as e:
            print(f"创建告警失败: {e}")
            return False
    
    def get_alarms_list(self, skip: int = 0, limit: int = 100) -> List[Alarm]:
        """获取告警列表"""
        try:
            return get_alarms(skip, limit)
        except Exception as e:
            print(f"获取告警列表失败: {e}")
            return []
    
    def get_alarm_detail(self, global_alarm_id: str) -> Optional[Alarm]:
        """获取告警详情"""
        try:
            return get_alarm_by_id(global_alarm_id)
        except Exception as e:
            print(f"获取告警详情失败: {e}")
            return None
    
    def get_alarms_count_by_query(self, query: AlarmQuery) -> int:
        """根据条件获取告警总数"""
        try:
            return get_alarms_count(
                global_alarm_id=query.global_alarm_id,
                alarm_status=query.alarm_status,
                alarm_title=query.alarm_title,
                alarm_type=query.alarm_type,
                alarm_level=query.alarm_level,
                region=query.region,
                datacenter=query.datacenter,
                device_name=query.device_name,
                device_type=query.device_type,
                device_vendor=query.device_vendor,
                dispatch_status=query.dispatch_status,
                resource_pool=query.resource_pool,
                start_time=query.start_time.isoformat() if query.start_time else None,
                end_time=query.end_time.isoformat() if query.end_time else None
            )
        except Exception as e:
            print(f"获取告警总数失败: {e}")
            return 0
    
    # ==================== 文件监听功能 ====================
    
    def start_file_monitoring(self, watch_path: Optional[str] = None) -> dict:
        """
        启动文件监听服务
        
        Args:
            watch_path: 要监听的目录路径，默认为固定路径
        
        Returns:
            dict: 包含成功/失败状态和消息
        """
        if self.monitoring:
            return {
                "success": False,
                "message": "文件监听服务已经在运行中"
            }
        
        # 使用动态路径（根据当前日期自动生成）
        if not watch_path:
            watch_path = get_wechat_file_base_path()
        
        # 检查路径是否存在
        if not os.path.exists(watch_path):
            return {
                "success": False,
                "message": f"监听路径不存在: {watch_path}"
            }
        
        try:
            # 定义监听函数
            def run_monitor():
                event_handler = ExcelFileHandler(self)
                observer = Observer()
                observer.schedule(event_handler, watch_path, recursive=False)
                observer.start()
                print(f"📂 开始监听文件夹: {watch_path}")
                print("📌 监听规则: 只处理以'告警导出'开头的.xlsx文件")
                
                # 保持监听运行
                try:
                    while self.monitoring:
                        observer.join(timeout=1)
                finally:
                    observer.stop()
                    observer.join()
                    print("⏹️ 停止监听")
            
            # 在后台线程启动监听
            self.monitor_thread = threading.Thread(target=run_monitor, daemon=True)
            self.monitor_thread.start()
            self.monitoring = True
            
            return {
                "success": True,
                "message": f"文件监听服务已启动，监听路径: {watch_path}"
            }
        except Exception as e:
            return {
                "success": False,
                "message": f"启动文件监听失败: {str(e)}"
            }
    
    def stop_file_monitoring(self) -> dict:
        """
        停止文件监听服务
        
        Returns:
            dict: 包含成功/失败状态和消息
        """
        if not self.monitoring:
            return {
                "success": False,
                "message": "文件监听服务未运行"
            }
        
        try:
            self.monitoring = False
            # 等待监听线程结束（最多等待2秒）
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread.join(timeout=2)
            
            return {
                "success": True,
                "message": "文件监听服务已停止"
            }
        except Exception as e:
            return {
                "success": False,
                "message": f"停止文件监听失败: {str(e)}"
            }
    
    def get_monitoring_status(self) -> dict:
        """
        获取文件监听状态
        
        Returns:
            dict: 监听状态信息
        """
        return {
            "monitoring": self.monitoring,
            "message": "正在监听" if self.monitoring else "未启动监听"
        }
    
    def get_latest_file(self) -> dict:
        """
        获取最新发现的告警导出文件
        
        Returns:
            dict: 最新文件信息
        """
        if self.latest_file:
            result = self.latest_file.copy()
            self.latest_file = None  # 读取后清空
            return {"has_new_file": True, "file": result}
        else:
            return {"has_new_file": False, "file": None}
    
    # ==================== 邮件发送功能 ====================
    
    def send_analysis_email(
        self,
        analysis_dir: Optional[str] = None,
        sender_email: Optional[str] = None,
        sender_password: Optional[str] = None,
        recipients: Optional[List[str]] = None,
        cc_recipients: Optional[List[str]] = None
    ) -> dict:
        """
        发送分析报告邮件（调用send_mail.py的业务逻辑）
        
        Args:
            analysis_dir: 分析结果目录路径，默认使用当前月份的analysis_results目录
            sender_email: 发件人邮箱，默认使用config.ini中的配置
            sender_password: 发件人密码，默认使用config.ini中的配置
            recipients: 收件人列表，默认使用config.ini中的配置
            cc_recipients: 抄送人列表，默认使用config.ini中的配置
        
        Returns:
            dict: 包含成功/失败状态和消息
        """
        # 默认分析目录（使用动态路径）
        if not analysis_dir:
            analysis_dir = get_analysis_results_path()
        
        # 获取配置文件中的邮件配置
        email_config = get_email_config()
        
        # 如果未提供参数，使用配置文件中的默认值
        if not sender_email:
            sender_email = email_config['sender_email']
        
        if not sender_password:
            sender_password = email_config['sender_password']
        
        if not recipients:
            recipients = email_config['recipients']
        
        if not cc_recipients:
            cc_recipients = email_config['cc_recipients']
        
        # 检查目录是否存在
        if not os.path.exists(analysis_dir):
            return {
                "success": False,
                "message": f"分析结果目录不存在: {analysis_dir}"
            }
        
        try:
            # 调用send_mail.py的压缩函数
            zip_file = send_mail.compress_analysis_results(analysis_dir)
            
            # 调用send_mail.py的发送邮件函数
            send_mail.send_analysis_email(
                sender_email=sender_email,
                sender_password=sender_password,
                recipients=recipients,
                cc_recipients=cc_recipients,
                zip_file=zip_file
            )
            
            return {
                "success": True,
                "message": "邮件发送成功"
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"发送邮件失败: {str(e)}"
            }
    
    # ==================== 本地大模型分析功能 ====================
    
    def analyze_alarms_with_llm(self, file_path: Optional[str] = None) -> dict:
        """
        调用本地大模型分析告警数据并生成Markdown文档（调用alarm_analyze.py的analyze_excel_file业务逻辑）
        
        Args:
            file_path: Excel文件路径，如果为None则自动查找最新的告警导出文件
        
        Returns:
            dict: 包含成功/失败状态和消息
        """
        try:
            # 直接调用alarm_analyze.py的analyze_excel_file函数
            # 使用默认的Excel文件路径（在analyze_excel_file函数中已定义）
            # analyze_excel_file会自动：
            #   1. 读取Excel文件到DataFrame
            #   2. 调用analyze_dataframe获取analysis_results
            #   3. 调用generate_markdown_report生成报告
            #   4. generate_markdown_report内部调用call_local_llm进行LLM分析
            
            print("开始调用analyze_excel_file进行分析...")
            
            # 如果没有提供文件路径，则查找最新的告警导出Excel文件
            if not file_path:
                file_path = find_latest_alarm_excel()
                
                if not file_path:
                    return {
                        "success": False,
                        "message": "未找到告警导出Excel文件，请确认文件是否存在"
                    }
            
            print(f"使用Excel文件: {file_path}")
            
            # 调用analyze_excel_file进行分析
            alarm_analyze.analyze_excel_file(file_path)
            
            # 获取输出目录路径（与Excel文件在同一目录下的analysis_results文件夹）
            output_dir = os.path.join(os.path.dirname(file_path), 'analysis_results')
            markdown_path = os.path.join(output_dir, 'analysis_report.md')
            
            # 验证报告是否生成成功
            if os.path.exists(markdown_path):
                return {
                    "success": True,
                    "message": f"分析报告生成成功，文件保存在: {markdown_path}",
                    "markdown_path": markdown_path,
                    "output_dir": output_dir
                }
            else:
                # 如果报告不存在，也返回成功（可能正在生成中）
                return {
                    "success": True,
                    "message": "分析任务已启动，请稍后查看报告文件",
                    "output_dir": output_dir
                }
            
        except Exception as e:
            import traceback
            error_detail = traceback.format_exc()
            print(f"调用大模型分析失败: {e}")
            print(f"详细错误: {error_detail}")
            return {
                "success": False,
                "message": f"调用大模型分析失败: {str(e)}"
            }
    
    # ==================== 柱状图数据分析 ====================
    
    def get_chart_analysis(self) -> dict:
        """
        获取柱状图数据分析（四大场景）
        
        场景1：告警标题趋势图 - TOP20告警标题
        场景2：设备告警趋势图 - TOP20设备名称
        场景3：设备厂商（虚层）趋势图 - TOP20设备厂商
        场景4：告警级别趋势图 - 所有级别分布
        
        Returns:
            dict: 包含四个场景的柱状图数据
        """
        try:
            import sqlite3
            from backend.database.connection import DB_PATH
            
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            
            # 场景1：告警标题趋势图 - TOP20
            cursor.execute("""
                SELECT alarm_title, COUNT(*) as count
                FROM alarms
                GROUP BY alarm_title
                ORDER BY count DESC
                LIMIT 20
            """)
            alarm_title_data = cursor.fetchall()
            chart1_data = {
                "labels": [row[0] for row in alarm_title_data],
                "values": [row[1] for row in alarm_title_data]
            }
            
            # 场景2：设备告警趋势图 - TOP20设备名称
            cursor.execute("""
                SELECT device_name, COUNT(*) as count
                FROM alarms
                GROUP BY device_name
                ORDER BY count DESC
                LIMIT 20
            """)
            device_name_data = cursor.fetchall()
            chart2_data = {
                "labels": [row[0] for row in device_name_data],
                "values": [row[1] for row in device_name_data]
            }
            
            # 场景3：设备厂商（虚层）趋势图 - TOP20
            cursor.execute("""
                SELECT device_vendor, COUNT(*) as count
                FROM alarms
                GROUP BY device_vendor
                ORDER BY count DESC
                LIMIT 20
            """)
            vendor_data = cursor.fetchall()
            chart3_data = {
                "labels": [row[0] for row in vendor_data],
                "values": [row[1] for row in vendor_data]
            }
            
            # 场景4：告警级别趋势图 - 所有级别分布
            cursor.execute("""
                SELECT alarm_level, COUNT(*) as count
                FROM alarms
                GROUP BY alarm_level
                ORDER BY 
                    CASE alarm_level
                        WHEN 'critical' THEN 1
                        WHEN 'major' THEN 2
                        WHEN 'minor' THEN 3
                        WHEN 'warning' THEN 4
                        ELSE 5
                    END
            """)
            level_data = cursor.fetchall()
            
            # 级别中文映射
            level_name_map = {
                'critical': '严重',
                'major': '重要',
                'minor': '次要',
                'warning': '警告'
            }
            
            chart4_data = {
                "labels": [level_name_map.get(row[0], row[0]) for row in level_data],
                "values": [row[1] for row in level_data]
            }
            
            # 获取总数
            cursor.execute("SELECT COUNT(*) FROM alarms")
            total_count = cursor.fetchone()[0]
            
            conn.close()
            
            return {
                "success": True,
                "total_alarms": total_count,
                "charts": {
                    "alarm_title_trend": chart1_data,
                    "device_alarm_trend": chart2_data,
                    "vendor_trend": chart3_data,
                    "level_trend": chart4_data
                }
            }
            
        except Exception as e:
            print(f"获取柱状图数据失败: {e}")
            return {
                "success": False,
                "message": f"分析失败: {str(e)}",
                "total_alarms": 0,
                "charts": {
                    "alarm_title_trend": {"labels": [], "values": []},
                    "device_alarm_trend": {"labels": [], "values": []},
                    "vendor_trend": {"labels": [], "values": []},
                    "level_trend": {"labels": [], "values": []}
                }
            }
